package objects;

import static objects.AdapletConstants.sNewLine;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import sections.ISection.Section;

public class Relationship implements IObject, IHasAttributes
{
	/**
	 * 
	 */
	private static final long serialVersionUID = -4963496665967943119L;
	private String fRelationshipName;
	private String fTableName;

	private String fId;
	private boolean fIdIsMapped;
	private String fDefaultType;

	private String fFromType;
	private String fFromId;
	private String fToType;
	private String fToId;

	private Map<String, String> fAttributeList;

	public Relationship()
	{
		fRelationshipName = "";
		fTableName = "";
		fId = "";
		fDefaultType = "";
		fFromType = "";
		fFromId = "";
		fToType = "";
		fToId = "";

		fIdIsMapped = true;

		fAttributeList = new LinkedHashMap<String, String>();
	}

	public void setIdIsMapped(boolean isMapped)
	{
		fIdIsMapped = isMapped;
	}

	public boolean isMapped()
	{
		return fIdIsMapped;
	}

	public String getTableName()
	{
		return fTableName;
	}

	public void setTableName(String fTableName)
	{
		this.fTableName = fTableName;
	}

	public String getId()
	{
		return fId;
	}

	public void setId(String fId)
	{
		this.fId = fId;
	}

	public String getDefaultType()
	{
		return fDefaultType;
	}

	public void setDefaultType(String fDefaultType)
	{
		this.fDefaultType = fDefaultType;
	}

	public String getFromType()
	{
		return fFromType;
	}

	public void setFromType(String fFromType)
	{
		this.fFromType = fFromType;
	}

	public String getFromId()
	{
		return fFromId;
	}

	public void setFromId(String fFromId)
	{
		this.fFromId = fFromId;
	}

	public String getToType()
	{
		return fToType;
	}

	public void setToType(String fToType)
	{
		this.fToType = fToType;
	}

	public String getToId()
	{
		return fToId;
	}

	public void setToId(String fToId)
	{
		this.fToId = fToId;
	}

	public String getAttributeColumn(String attrName)
	{
		return fAttributeList.get(attrName);
	}

	public void addAttribute(String attrName, String columnName)
	{
		fAttributeList.put(attrName, columnName);
	}

	public void setRelationshipName(String relationshipName)
	{
		fRelationshipName = relationshipName;
	}

	public String getRelationshipName()
	{
		return fRelationshipName;
	}

	@Override
	public String toString()
	{
		return buildRelationshipDefinition();
	}

	protected String buildComment()
	{
		StringBuffer commentBuf = new StringBuffer(100);

		commentBuf.append("#############################################");
		commentBuf.append(sNewLine);

		commentBuf.append("# Relationship Definition: \"");
		commentBuf.append(fRelationshipName);
		commentBuf.append("\"");
		commentBuf.append(sNewLine);

		commentBuf.append("# Using Table: ");
		commentBuf.append(fTableName);
		commentBuf.append(sNewLine);

		commentBuf.append("#############################################");
		commentBuf.append(sNewLine);

		return commentBuf.toString();
	}

	public String buildRelationshipDefinition()
	{
		StringBuffer relationshipDef = new StringBuffer(1000);

		relationshipDef.append(buildComment());

		relationshipDef.append("relationship \"");
		relationshipDef.append(fRelationshipName);
		relationshipDef.append("\" {");
		relationshipDef.append(sNewLine);

		relationshipDef.append("\tid ");
		relationshipDef.append(fTableName);
		relationshipDef.append("(");
		relationshipDef.append(fId);
		relationshipDef.append(")");
		if (fIdIsMapped)
		{
			relationshipDef.append(" mapped");
		}
		relationshipDef.append(";");
		relationshipDef.append(sNewLine);

		if (fDefaultType != null && !fDefaultType.isEmpty())
		{
			relationshipDef.append("\tdefault type \"");
			relationshipDef.append(fDefaultType);
			relationshipDef.append("\";");
			relationshipDef.append(sNewLine);
		}

		relationshipDef.append("\tfrom \"");
		relationshipDef.append(fFromType);
		relationshipDef.append("\" in ");
		relationshipDef.append(fTableName);
		relationshipDef.append("(");
		relationshipDef.append(fFromId);
		relationshipDef.append(");");
		relationshipDef.append(sNewLine);

		relationshipDef.append("\tto \"");
		relationshipDef.append(fToType);
		relationshipDef.append("\" in ");
		relationshipDef.append(fTableName);
		relationshipDef.append("(");
		relationshipDef.append(fToId);
		relationshipDef.append(");");
		relationshipDef.append(sNewLine);

		for (String attrName : fAttributeList.keySet())
		{
			String columnName = fAttributeList.get(attrName);

			relationshipDef.append("\tattribute \"");
			relationshipDef.append(attrName);
			relationshipDef.append("\" ");
			relationshipDef.append(columnName);
			relationshipDef.append(";");
			relationshipDef.append(sNewLine);
		}

		relationshipDef.append("}");
		relationshipDef.append(sNewLine);

		return relationshipDef.toString();
	}

	public Set<String> getAttributeList()
	{
		return fAttributeList.keySet();
	}

	public String[] getAttributeNames()
	{
		return getAttributeList().toArray(new String[0]);
	}

	@Override
	public String getObjectName()
	{
		return getRelationshipName();
	}

	@Override
	public Section getSectionType()
	{
		return Section.REL;
	}

	private void readObject(ObjectInputStream iStream) throws IOException, ClassNotFoundException
	{
		iStream.defaultReadObject();
		validateState();
	}

	private void writeObject(ObjectOutputStream oStream) throws IOException
	{
		oStream.defaultWriteObject();
	}

	private void validateState()
	{
		// TODO
	}
	
	public void removeAttribute(String attrName)
	{
		fAttributeList.remove(attrName);
	}
}
